#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <ctype.h>

intmax_t strtol(const char *nptr, char **endptr, int base)
{
    const char *s = NULL;
    int acc, cutoff;
    int c;
    int neg, any, cutlim;

    // skip lending space
    s = nptr;
    do
    {
        c = (uint8_t)*s++;
    } while (isspace(c));

    // pick up lending +/- sign
    if (c == '-')
    {
        neg = 1;
        c = *s++;
    }
    else
    {
        neg = 0;
        if (c == '+')
        {
            c = *s++;
        }
    }

    if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X'))
    {
        c = s[1];
        s += 2;
        base = 16;
    }

    if (base == 0)
        base = c == '0' ? 8 : 10;

    cutoff = neg ? LONG_MIN : LONG_MAX;
    cutoff /= base;
    cutlim = cutoff % base;

    if (neg)
    {
        if (cutlim > 0)
        {
            cutlim -= base;
            cutoff += 1;
        }
        cutlim = -cutlim;
    }

    for (acc = 0, any = 0;; c = *s++)
    {
        if (isdigit(c))
        {
            c -= '0';
        }
        else
        {
            if (isalpha(c))
            {
                c -= isupper(c) ? 'A' - 10 : 'a' - 10;
            }
            else
                break;
        }

        if (c >= base)
            break;

        if (any < 0)
            continue;

        if (neg)
        {
            if (acc < cutoff || (acc == cutoff && c > cutlim))
            {
                any = -1;
                acc = LONG_MIN;
                errno = ERANGE;
            }
            else
            {
                any = 1;
                acc *= base;
                acc -= c;
            }
        }
        else
        {
            if (acc > cutoff || (acc == cutoff && c > cutlim))
            {
                any = -1;
                acc = LONG_MAX;
                errno = ERANGE;
            }
            else
            {
                any = 1;
                acc *= base;
                acc += c;
            }
        }
    }

    if (endptr)
        *endptr = (char *)(any ? s - 1 : nptr);

    return acc;
}